// 全部缓动类型
package main

import (
	"runtime"
	"time"

	app "gitee.com/go_888/xcgui/xcgui/app"
	drawx "gitee.com/go_888/xcgui/xcgui/drawx"
	ease "gitee.com/go_888/xcgui/xcgui/ease"
	widget "gitee.com/go_888/xcgui/xcgui/widget"
	window "gitee.com/go_888/xcgui/xcgui/window"
	xc "gitee.com/go_888/xcgui/xcgui/xc"
	xcc "gitee.com/go_888/xcgui/xcgui/xcc"
)

var (
	w *window.Window

	m_easeFlag           = xcc.X缓动类型_快到慢 // 缓动方式
	m_easeType   int32   = 11                // 缓动类型
	m_pos        int32   = 0                 // 当前位置
	m_time       int32   = 60                // 缓动点数量
	m_time_pos   int32   = 0                 // 当前点
	m_rect       xc.X结构_矩形                     // 窗口客户区坐标
	m_windowType = 2                         // 窗口水平或垂直缓动
)

func main() {
	// 这是必要的, 这将保证main函数中对UI库命令的调用是在一个系统线程中执行的。
	// 如果不在一个系统线程中执行, 那程序大概率卡死.
	// 其他例子里没有加是因为简单的例子确实不需要这两句代码, 总之从初始化到Run需要保证是在一个系统线程中执行.
	// 程序运行就窗口卡死未响应就是go的运行时调度的原因, 还没到Run就切换到其他线程了, 比如你在Run前http访问网页了main中加上这两句就不会有问题, 不加就可能出问题.
	// 因为下面用了time.Sleep(), go的运行时可能会进行调度, 就跳到其他线程了, 所以必须用这个.
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	a := app.X创建(true)
	a.X设置绘制频率(10)
	w = window.X创建窗口(0, 0, 700, 450, "炫彩缓动测试", 0, xcc.X窗口样式_默认样式|xcc.X窗口样式_拖动窗口)

	var left int32 = 30
	var top int32 = 35
	CreateButton(2, 11, left, top, 100, "Linear")
	left += 105
	CreateButton(2, 12, left, top, 100, "Quadratic")
	left += 105
	CreateButton(2, 13, left, top, 100, "Cubic")
	left += 105
	CreateButton(2, 14, left, top, 100, "Quartic")
	left += 105
	CreateButton(2, 15, left, top, 100, "Quintic")
	left += 105

	left = 30
	top += 30
	CreateButton(2, 16, left, top, 100, "Sinusoidal")
	left += 105
	CreateButton(2, 17, left, top, 100, "Exponential")
	left += 105
	CreateButton(2, 18, left, top, 100, "Circular")
	left += 105

	left = 30
	top += 30
	CreateButton(2, 19, left, top, 100, "Elastic")
	left += 105
	CreateButton(2, 20, left, top, 100, "Back")
	left += 105
	CreateButton(2, 21, left, top, 100, "Bounce")
	left += 105

	left = 30
	top += 40
	CreateButton(1, 0, left, top, 100, "easeIn")
	left += 105
	CreateButton(1, 1, left, top, 100, "easeOut")
	left += 105
	CreateButton(1, 2, left, top, 100, "easeInOut")
	left += 105

	btn := widget.X创建按钮(445, top, 100, 24, "快速", w.X句柄)
	btn.X设置类型EX(xcc.X对象扩展类型_复选按钮)
	btn.X设置选中(true)
	btn.X事件_选中(OnBtnCheckSlow)

	btn = widget.X创建按钮(445, 65, 100, 24, "从左向右", w.X句柄)
	btn.X设置类型EX(xcc.X对象扩展类型_单选按钮)
	btn.X设置组ID(3)
	btn.X事件_选中(OnBtnCheck_LeftToRight)

	btn = widget.X创建按钮(445, 92, 100, 24, "从上向下", w.X句柄)
	btn.X设置类型EX(xcc.X对象扩展类型_单选按钮)
	btn.X设置组ID(3)
	btn.X设置选中(true)
	btn.X事件_选中(OnBtnCheck_TopToBottom)

	btn = widget.X创建按钮(550, 65, 110, 50, "Run - 窗口缓动", w.X句柄)
	btn.X事件_被单击(OnBtnStartWindow)

	btn = widget.X创建按钮(550, 120, 110, 50, "Run - 缓动曲线", w.X句柄)
	btn.X事件_被单击(OnBtnStart)

	w.X调整布局()
	w.X显示方式(xcc.SW_SHOW)

	// 窗口绘制事件
	w.X事件_绘制(OnDrawWindow)

	// 获取窗口坐标
	rc := w.GetRectDPI()
	// 第一次缓动
	for t := 0; t <= 30; t++ {
		v := ease.X缓动弹跳(float32(t)/30.0, xcc.X缓动类型_快到慢)
		y := int32(v * float32(rc.X上))
		w.X移动窗口(rc.X左, y).X重绘(true)
		time.Sleep(time.Millisecond * 10)
	}

	a.X运行()
	a.X退出()
}

// 创建按钮
func CreateButton(nGroup, id, x, y, cx int32, title string) {
	btn := widget.X创建按钮(x, y, cx, 22, title, w.X句柄)
	// 设置为单选按钮
	btn.X设置类型EX(xcc.X对象扩展类型_单选按钮)
	// 设置按钮组id
	btn.X设置组ID(nGroup)
	// 设置元素ID
	btn.X设置ID(id)

	if id == 1 || id == 21 {
		btn.X设置选中(true)
	}
	// 注册按钮选中事件
	btn.X事件_选中1(OnButtonCheck)
}

// 按钮选中事件
func OnButtonCheck(hEle int, bCheck bool, pbHandled *bool) int {
	if !bCheck {
		return 0
	}
	id := xc.X窗口组件_取ID(hEle)

	if id <= 2 {
		m_easeFlag = xcc.X缓动类型(id)
	} else {
		m_easeType = id - 10
	}

	w.X重绘(true)
	return 0
}

// 快速
func OnBtnCheckSlow(bCheck bool, pbHandled *bool) int {
	if bCheck {
		m_time = 60
	} else {
		m_time = 120
	}
	return 0
}

// 从左向右
func OnBtnCheck_LeftToRight(bCheck bool, pbHandled *bool) int {
	if bCheck {
		m_windowType = 1
	}
	return 0
}

// 从上向下
func OnBtnCheck_TopToBottom(bCheck bool, pbHandled *bool) int {
	if bCheck {
		m_windowType = 2
	}
	return 0
}

// 窗口缓动
func OnBtnStartWindow(pbHandled *bool) int {
	rect := w.GetRectDPI()

	time2 := m_time / 2
	for t := int32(0); t <= time2; t++ {
		var v float32
		switch m_easeType {
		case 1:
			v = ease.X缓动线性(float32(t) / float32(time2))
		case 2:
			v = ease.X缓动二次方曲线(float32(t)/float32(time2), m_easeFlag)
		case 3:
			v = ease.X缓动三次方曲线(float32(t)/float32(time2), m_easeFlag)
		case 4:
			v = ease.X缓动四次方曲线(float32(t)/float32(time2), m_easeFlag)
		case 5:
			v = ease.X缓动五次方曲线(float32(t)/float32(time2), m_easeFlag)
		case 6:
			v = ease.X缓动正弦曲线(float32(t)/float32(time2), m_easeFlag)
		case 7:
			v = ease.X缓动突击曲线(float32(t)/float32(time2), m_easeFlag)
		case 8:
			v = ease.X缓动圆环(float32(t)/float32(time2), m_easeFlag)
		case 9:
			v = ease.X缓动强力回弹(float32(t)/float32(time2), m_easeFlag)
		case 10:
			v = ease.X缓动回弹(float32(t)/float32(time2), m_easeFlag)
		case 11:
			v = ease.X缓动弹跳(float32(t)/float32(time2), m_easeFlag)
		}

		if m_windowType == 1 {
			x := int32(v * float32(rect.X左))
			w.X移动窗口(x, rect.X上)
		} else {
			y := int32(v * float32(rect.X上))
			w.X移动窗口(rect.X左, y)
		}
		w.X重绘(true)
		time.Sleep(10 * time.Millisecond)
	}
	return 0
}

// 缓动曲线
func OnBtnStart(pbHandled *bool) int {
	var width float32 = 400.0
	for t := int32(0); t <= m_time; t++ {
		var v float32
		switch m_easeType {
		case 1:
			v = ease.X缓动线性(float32(t) / float32(m_time))
		case 2:
			v = ease.X缓动二次方曲线(float32(t)/float32(m_time), m_easeFlag)
		case 3:
			v = ease.X缓动三次方曲线(float32(t)/float32(m_time), m_easeFlag)
		case 4:
			v = ease.X缓动四次方曲线(float32(t)/float32(m_time), m_easeFlag)
		case 5:
			v = ease.X缓动五次方曲线(float32(t)/float32(m_time), m_easeFlag)
		case 6:
			v = ease.X缓动正弦曲线(float32(t)/float32(m_time), m_easeFlag)
		case 7:
			v = ease.X缓动突击曲线(float32(t)/float32(m_time), m_easeFlag)
		case 8:
			v = ease.X缓动圆环(float32(t)/float32(m_time), m_easeFlag)
		case 9:
			v = ease.X缓动强力回弹(float32(t)/float32(m_time), m_easeFlag)
		case 10:
			v = ease.X缓动回弹(float32(t)/float32(m_time), m_easeFlag)
		case 11:
			v = ease.X缓动弹跳(float32(t)/float32(m_time), m_easeFlag)
		}

		m_pos = int32(v * width)
		m_time_pos = t
		time.Sleep(10 * time.Millisecond)

		rc := m_rect
		rc.X上 = 170
		w.X重绘指定区域(&rc, true)
	}
	return 0
}

// 绘制
func OnDrawWindow(hDraw int, pbHandled *bool) int {
	*pbHandled = true

	var rect xc.X结构_矩形
	w.X取客户区坐标(&rect)

	draw := drawx.X创建并按图形绘制模块句柄(hDraw)
	draw.X设置画刷颜色(xc.RGBA颜色(230, 230, 230, 255))
	draw.X填充矩形(&rect)
	m_rect = rect

	draw.X设置画刷颜色(xc.RGBA颜色(200, 200, 200, 255))
	draw.X矩形边框(&rect)

	draw.X设置画刷颜色(xc.RGBA颜色(0, 0, 200, 255))
	draw.X文本输出EX(260, 10, "炫彩界面库(XCGUI) - 缓动测试")

	var rc xc.X结构_矩形
	rc.X左 = 150
	rc.X上 = 190
	rc.X右 = rc.X左 + 400 + 30
	rc.X下 = rc.X上 + 50

	rcBorder := rc
	rcBorder.X左 -= 2
	rcBorder.X上 -= 2
	rcBorder.X右 += 2
	rcBorder.X下 += 2
	draw.X设置画刷颜色(xc.RGBA颜色(0, 0, 200, 255))
	draw.X矩形边框(&rcBorder)

	rcFill := rc
	rcFill.X左 = rcFill.X左 + m_pos
	rcFill.X右 = rcFill.X左 + 30
	draw.X设置画刷颜色(xc.RGBA颜色(128, 0, 0, 255))
	draw.X填充矩形(&rcFill)

	var rcBorder_Line xc.X结构_矩形
	rcBorder_Line.X左 = 150
	rcBorder_Line.X右 = 150 + 400
	rcBorder_Line.X上 = 255
	rcBorder_Line.X下 = 255 + 180

	rcBorder = rcBorder_Line
	rcBorder.X右++
	rcBorder.X下++
	draw.X设置画刷颜色(xc.RGBA颜色(180, 180, 180, 255))
	draw.X矩形边框(&rcBorder)

	pts := make([]xc.X结构_坐标F, 121)
	for t := int32(0); t <= m_time; t++ {
		var v float32
		switch m_easeType {
		case 1:
			v = ease.X缓动线性(float32(t) / float32(m_time))
		case 2:
			v = ease.X缓动二次方曲线(float32(t)/float32(m_time), m_easeFlag)
		case 3:
			v = ease.X缓动三次方曲线(float32(t)/float32(m_time), m_easeFlag)
		case 4:
			v = ease.X缓动四次方曲线(float32(t)/float32(m_time), m_easeFlag)
		case 5:
			v = ease.X缓动五次方曲线(float32(t)/float32(m_time), m_easeFlag)
		case 6:
			v = ease.X缓动正弦曲线(float32(t)/float32(m_time), m_easeFlag)
		case 7:
			v = ease.X缓动突击曲线(float32(t)/float32(m_time), m_easeFlag)
		case 8:
			v = ease.X缓动圆环(float32(t)/float32(m_time), m_easeFlag)
		case 9:
			v = ease.X缓动强力回弹(float32(t)/float32(m_time), m_easeFlag)
		case 10:
			v = ease.X缓动回弹(float32(t)/float32(m_time), m_easeFlag)
		case 11:
			v = ease.X缓动弹跳(float32(t)/float32(m_time), m_easeFlag)
		}

		pts[t].X坐标 = float32(rc.X左) + float32(t)*400.0/float32(m_time)
		pts[t].Y坐标 = float32(rcBorder_Line.X下) - v*180.0
	}

	draw.X启用平滑模式(true)
	draw.X设置画刷颜色(xc.RGBA颜色(128, 0, 0, 255))

	left := rc.X左 + int32(float32(m_time_pos)*400.0/float32(m_time))

	draw.X线条(left, rcBorder_Line.X上, left, rcBorder_Line.X下)
	draw.X曲线F(pts, m_time+1, 0.5)
	return 0
}
